﻿/****************************************************************
*   作者：Morain
*   创建时间：2018/2/13 17:10:08
*   描述说明：
*****************************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace ETSModel
{
  /// <summary>
  /// 环形Buffer
  /// </summary>
  public class RingBuffer
  {
    // 片大小
    public int ChunkSize = 8192;

    // 一片缓冲
    private readonly Queue<byte[]> bufferQueue = new Queue<byte[]>();
    // 一片缓冲的缓存，减少内存分配和GC的调用。
    private readonly Queue<byte[]> bufferCache = new Queue<byte[]>();

    // 指向一片缓冲，写入的下标
    public int LastIndex { get; set; }

    // 指向一片缓冲，读的下标
    public int FirstIndex { get; set; }

    // 指向环形中的最后一片缓冲。
    private byte[] lastBuffer;

    public RingBuffer()
    {
      this.AddLast();
    }

    /// <summary>
    /// 向环形缓冲中，最后一个位置添加一个新的缓冲区（一片缓冲）。
    /// </summary>
    public void AddLast()
    {
      byte[] buffer;
      if (this.bufferCache.Count > 0)
      {
        buffer = this.bufferCache.Dequeue();
      }
      else
      {
        buffer = new byte[this.ChunkSize];
      }
      this.bufferQueue.Enqueue(buffer);
      this.lastBuffer = buffer;
    }

    /// <summary>
    /// 移除开头的缓冲区
    /// </summary>
    public void RemoveFirst()
    {
      this.bufferCache.Enqueue(this.bufferQueue.Dequeue());
    }

    /// <summary>
    /// 计算环形缓冲区中一共的数据
    /// </summary>
    public int Count
    {
      get
      {
        int len = 0;
        if (this.bufferQueue.Count == 0)
          len = 0;
        else
        {
          len = (this.bufferQueue.Count - 1) * this.ChunkSize + this.LastIndex - this.FirstIndex;
        }

        if (len < 0)
          Log.Error($"Buffer Count < 0");
        return len;
      }
    }

    /// <summary>
    /// 获取读的buffer
    /// </summary>
    public byte[] First
    {
      get
      {
        if (this.bufferQueue.Count == 0)
        {
          this.AddLast();
        }
        return this.bufferQueue.Peek();
      }
    }

    /// <summary>
    /// 获取写入的buffer
    /// </summary>
    public byte[] Last
    {
      get
      {
        if (this.bufferQueue.Count == 0)
          this.AddLast();

        return this.lastBuffer;
      }
    }

    public void SendTo(byte[] buffer)
    {
      int alreadyCopyCount = 0;
      while (alreadyCopyCount < buffer.Length)
      {
        // 表示这个buffer已经写完
        if (this.LastIndex == this.ChunkSize)
        {
          this.AddLast();
          this.LastIndex = 0;
        }

        // 剩下的字节
        int n = buffer.Length - alreadyCopyCount;
        // 当前buffer足够，放下剩下的字节。
        if (this.ChunkSize - this.LastIndex > n)
        {
          Array.Copy(buffer, alreadyCopyCount, lastBuffer, this.LastIndex, n);
          this.LastIndex += n;
          alreadyCopyCount += n;
        }
        else // 当前缓冲区，不够放下剩下的数据。
        {
          Array.Copy(buffer, alreadyCopyCount, this.lastBuffer, this.LastIndex, this.ChunkSize - this.LastIndex);
          alreadyCopyCount += this.ChunkSize - this.LastIndex;
          this.LastIndex = this.ChunkSize;
        }
      }
    }

    public void SendTo(byte[] buffer, int offset, int count)
    {
      int alreadyCopyCount = 0;
      while (alreadyCopyCount < count)
      {
        if (this.LastIndex == ChunkSize)
        {
          this.AddLast();
          this.LastIndex = 0;
        }

        int n = count - alreadyCopyCount;
        if (ChunkSize - this.LastIndex > n)
        {
          Array.Copy(buffer, alreadyCopyCount + offset, this.lastBuffer, this.LastIndex, n);
          this.LastIndex += count - alreadyCopyCount;
          alreadyCopyCount += n;
        }
        else
        {
          Array.Copy(buffer, alreadyCopyCount + offset, this.lastBuffer, this.LastIndex, ChunkSize - this.LastIndex);
          alreadyCopyCount += ChunkSize - this.LastIndex;
          this.LastIndex = ChunkSize;
        }
      }
    }

    /// <summary>
    /// 读取缓冲里的数据
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="count"></param>
    public void RecvFrom(byte[] buffer, int count)
    {
      if (this.Count < count)
      {
        throw new Exception($"bufferQueue size < count");
      }

      if (buffer.Length < count)
      {
        throw new Exception($"buffer len < count");
      }

      int alreadyCopyCount = 0;
      while (alreadyCopyCount < count)
      {
        // 剩余的字节
        int n = count - alreadyCopyCount;
        // 读取缓冲区中，够读剩余的字节。
        if (this.ChunkSize - this.FirstIndex > n)
        {
          Array.Copy(this.First, this.FirstIndex, buffer, alreadyCopyCount, n);
          this.FirstIndex += n;
          alreadyCopyCount += n;
        }
        else // 缓冲区，可读长度不够。
        {
          Array.Copy(this.First, this.FirstIndex, buffer, alreadyCopyCount, this.ChunkSize - this.FirstIndex);
          alreadyCopyCount += this.ChunkSize - this.FirstIndex;
          this.FirstIndex = 0;
          this.RemoveFirst();
        }
      }
    }
  }
}
